#ifndef _SYS_FAN_OBJ_H_
#define _SYS_FAN_OBJ_H_

#include "Val.h"
#include "VTable.h"
#include "SysTypes.h"

#define OBJ_VTABLE(self)       ((FanObjVTable*)self.vtable)
#define OBJ_REF_VTABLE(self)   ((FanObjVTable*)((FanObj*)self)->vtable)


extern Type*    Obj_classType;
extern VTable*  Obj_classVTable;


/* [sys::Obj] Attributes */
struct FanObj
{
  VTable*       vtable;
};


/* [sys::Obj] Virtual-table */
typedef struct FanObjVTable
{
  VTable        super;
  Int           (*compare)(Obj self, Obj that);
  Bool          (*equals)(Obj self, NullableObj that);
  Int           (*hash)(Obj self);
  Str*          (*toStr)(Obj self);
  NullableObj   (*trap_1)(Obj self, Str* name);
  NullableObj   (*trap)(Obj self, Str* name, List* args);
  Obj           (*with)(Obj self, Func* f);

  /* Internal virtual methods */
  Bool          (*isImmutable)(Obj self);
  Obj           (*toImmutable)(Obj self);
} FanObjVTable;


/* [sys::Obj] Methods and fields */
void            Obj_make(Obj self);
Bool            Obj_equals(Obj self, NullableObj that);
Int             Obj_compare(Obj self, Obj that);
Int             Obj_hash(Obj self);
Str*            Obj_toStr(Obj self);
NullableObj     Obj_trap_1(Obj self, Str* name);
NullableObj     Obj_trap(Obj self, Str* name, List* args);
Obj             Obj_with(Obj self, Func* f);
Bool            Obj_isImmutable(Obj self);
Obj             Obj_toImmutable(Obj self);
Type*           Obj_typeof(Obj self);
void            Obj_echo_0(void);
void            Obj_echo(NullableObj x);


/* [sys::Obj] Extra methods */
FanObj*         Obj_allocate(size_t instanceSize, VTable* vtable);
void*           Obj_castToClass(NullableObj self, Type* type, Bool checked);
void*           Obj_castToMixin(NullableObj self, Type* type, Bool checked);


/* [sys::Obj] Type-system functions */
Type*           Obj_initType(void);
VTable*         Obj_initVTable(void);
void            Obj_initStatic(void);


#endif
